/**
  ******************************************************************************
  * @file    main.c
  * @author  AE Team
  * @version 1.0.3
  * @date    2024-05-28
  * @brief   本样例演示系统从 HSI48M 进入 DeepSleep 模式后系统的功耗
  *          将演示从 DeepSleep 唤醒后快速执行用户代码的方法(唤醒后使用HSI4MHz时钟)
  *          操作说明:
  *          1.下载完成后请拔掉调试器并按Reset按键执行程序
  *          2.KEY(PB04): 按下后的下降沿用于中断唤醒处于DeepSleep状态的MCU
  *          3.LED(PA03): 系统唤醒后首先执行用户紧急代码(本例中将LED_PB04置低)
  *                       之后开启全局中断，此时会响应KEY(PA03)的中断服务程序(将LED_PB04置高)。
  *                       通过测量KEY(PA03)的下降到LED(PB04)的下降沿得到的时间为：从触发唤醒到
  *                       唤醒后执行完第一条用户C语句的时间。
  *
  * @note    硬件平台：SYM32L010_StartKit_V1.0
  *          接线说明：断开J12、J13、J14、J17、J21、J22、J24、J26、J27
  *                    短接J25、J28
  *                    通过USB-C接口供电，将J3断开串联万用表测MCU功耗。
  *                    在环境温度约 27℃ 下实测从时钟源为HSI48M进入DeepSleep状态后功耗为300nA左右
  *
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2024 SIYIMicro.
  * All rights reserved.</center></h2>
  *
  *
  ******************************************************************************
  */


/******************************************************************************/
/* Include files                                                              */
/******************************************************************************/
#include "main.h"
#include "sym32l010_hal_sysctrl.h"
#include "sym32l010_hal_systick.h"
#include "sym32l010_hal_gpio.h"
#include "sym32l010_Startkit_board.h"


/******************************************************************************/
/* Local pre-processor symbols/macros ('#define')                             */
/******************************************************************************/

/******************************************************************************/
/* Global variable definitions (declared in header file with 'extern')        */
/******************************************************************************/

/******************************************************************************/
/* Local type definitions ('typedef')                                         */
/******************************************************************************/

/******************************************************************************/
/* Local function prototypes ('static')                                       */
/******************************************************************************/

/******************************************************************************/
/* Local variable definitions ('static')                                      */
/******************************************************************************/

/******************************************************************************/
/* Local pre-processor symbols/macros ('#define')                             */
/******************************************************************************/

/******************************************************************************/
/* Function implementation - global ('extern') and local ('static')           */
/******************************************************************************/


/*******************************************************************************
 ** \brief  Main function of project
 **
 ** \return uint32_t return value, if needed
 **
 **
 ******************************************************************************/
int32_t main(void)
{
    // PCLK 输出到PA02管脚，请通过PA02观察PCLK频率
    HAL_SysCtrl_ClkOut_PCLK_PA02();

    // 初始化板载LED
    Bsp_Led_Init();

    // 初始化板载KEY, 开启下降沿中断
    Bsp_Key_Init();
    BSP_KEY_PORT->FALLIE |= (BSP_KEY_PIN);
    NVIC_ClearPendingIRQ(BSP_KEY_IRQn);
    NVIC_EnableIRQ(BSP_KEY_IRQn);

    HAL_SysCtrl_ConfigWaitCycle(48000000);                            // 根据目标频率设置FlashWait
    HAL_SysCtrl_HSI_SetDiv(HSIOSC_TO_HSI48MHZ);                       // 开启内部高速时钟HSI = HSIOSC / 1 = 48M
    HAL_SysCtrl_LSE_Disable();                                        // 软件关闭LSE，以防其他样例开启了LSE没有被关闭导致本样例功耗不符合预期

    // 初始化SysTick
    HAL_InitTick(48000000);

    while (1)
    {
        //------------------------------------------------------------
        // LED慢速闪烁5次之后再进入Deepsleep，防止因复位之后直接进入Deepsleep而导致SWD无法连接
        for (uint32_t i = 0; i < 5; i++)
        {
            BSP_LED_SETLOW();
            HAL_Delay(300);
            BSP_LED_SETHIGH();
            HAL_Delay(300);
        }

        //------------------------------------------------------------
        // 系统进入Deepsleep前, 关闭所有没使用的时钟以降低功耗, 仅开启需要使用的时钟
        HAL_SYSCTRL_AHBALL_CLK_DISABLE();
        HAL_SYSCTRL_APB1ALL_CLK_DISABLE();
        HAL_SYSCTRL_APB2ALL_CLK_DISABLE();
        HAL_SYSCTRL_GPIOA_CLK_ENABLE();
        HAL_SYSCTRL_GPIOB_CLK_ENABLE();

        __disable_irq();                                              // 关闭全局总中断
        HAL_SysCtrl_EnterDeepSleep(WAKEUPCLK_HSI4MHz);                // 进入DeepSleep模式, 唤醒后系统时钟使用HSI4MHz执行代码，避免时钟切换导致的耗时

        // 唤醒后以HSI4MHz执行用户紧急代码，执行完毕后打开总中断
        BSP_LED_SETLOW();                                             // 执行用户紧急代码
        __enable_irq();                                               // 打开全局总中断

        //------------------------------------------------------------
        // 执行完用户紧急代码，将系统时钟重新调整回HSI48M
        HAL_SysCtrl_HSI_SetDiv(HSIOSC_TO_HSI48MHZ);

        //------------------------------------------------------------
        // 使用HSI48M执行用户后续代码
        for (uint32_t i = 0; i < 5; i++)
        {
            BSP_LED_SETHIGH();
            HAL_Delay(100);
            BSP_LED_SETLOW();
            HAL_Delay(100);
        }
    }
}


/*******************************************************************************
  * @brief  板载按键下降沿的中断服务程序回调函数
  * @param  None
  * @retval None
  */
void KEY_IRQHandlerCallBack(void)
{
    if (HAL_GPIO_GET_FLAG(BSP_KEY_PORT, BSP_KEY_PIN))
    {
        BSP_LED_SETLOW();
        HAL_GPIO_CLR_FLAG(BSP_KEY_PORT, BSP_KEY_PIN);
    }
}


/*******************************************************************************
 ** EOF (not truncated)
 ******************************************************************************/
#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
    /* USER CODE BEGIN */
    /* User can add his own implementation to report the file name and line number,
       tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
    /* USER CODE END */
}
#endif /* USE_FULL_ASSERT */


/************************ (C) COPYRIGHT SIYIMicro *****END OF FILE*************/
